/**
 * 20220117:从原strips中分离
 * 20220721:add annotation for constructor
 */
import HardLineMaterial from "./hard-line-material";

/**
 * 多段线材质
 */
export default class StripsMaterial extends HardLineMaterial{
    /**
     * 
     * @param {*} values 可选参数对象
     *      {
     *          dropCorrectionHead:0.01, {number} 起始端丢弃长度
     *          dropCorrectionTail:0.01, {number} 结束端丢弃长度
     *          其它父类的参数
     *      }
     */
    constructor(values={}){
        super(values);
    }

    //.................................................public.....................................................

    get dropCorrectionHead(){
        return this._dropCorrectionHead;
    }
    set dropCorrectionHead(num){
        this.uniforms.dropCorrectionHead.value=this._dropCorrectionHead=num;
    }
    get dropCorrectionTail(){
        return this._dropCorrectionTail;
    }
    set dropCorrectionTail(num){
        this.uniforms.dropCorrectionTail.value=this._dropCorrectionTail=num;
    }

    //.................................................private.....................................................

    _initVariable(values) {
        super._initVariable(values);
        this._dropCorrectionHead=values.dropCorrectionHead||0.01;
        this._dropCorrectionTail=values.dropCorrectionTail||0.01;
    }

    _getExclusiveKeys() {
        let ks= super._getExclusiveKeys();
        ks.push('dropCorrectionHead','dropCorrectionTail');
        return ks;
    }
    _initUniforms() {
        super._initUniforms();
        this.uniforms.dropCorrectionHead={value:this._dropCorrectionHead};
        this.uniforms.dropCorrectionTail={value:this._dropCorrectionTail};
        this.needsUpdate=true;
    }
    _initVertexShader() {
        this.vertexShader=`
            attribute vec3 nextPosition;
            attribute float offset;
            attribute float lineDistance;
            attribute float count;
            uniform vec3 color;
            uniform float width;
            uniform float perspectiveFactor;
            uniform bool sizeAttenuation;
            varying vec3 vColor;
            varying float vDistance;
            varying float vDrop;
            float computeAspect(){
               float aspect=0.5625;
               if(projectionMatrix[3][3]==0.0){
                  float _tan=projectionMatrix[1][1];
                  float as_tan=1.0/projectionMatrix[0][0];
                  aspect=1.0/(as_tan*_tan);
               }else{
                  float _height=1.0/projectionMatrix[1][1];
                  float _width=1.0/projectionMatrix[0][0];
                  aspect=_height/_width;
               }
               return aspect;
            }
            void main(){
               vec4 mvPosition=modelViewMatrix*vec4(position,1.0);
               vec4 pmvPosition=projectionMatrix*mvPosition;
               vec4 mvNextPosition=modelViewMatrix*vec4(nextPosition,1.0);
               vec4 nxtP=projectionMatrix*mvNextPosition;
               vec4 curP=pmvPosition;
               vec3 nxt=vec3(nxtP.x/nxtP.w,nxtP.y/nxtP.w,nxtP.z/nxtP.w);
               vec3 cur=vec3(curP.x/curP.w,curP.y/curP.w,curP.z/curP.w);
               vec3 dirOri=nxt-cur;
               vec3 look=vec3(0.0,0.0,1.0);

               vec3 dirCC=mvPosition.xyz/mvPosition.w;
               vec3 dirCN=mvNextPosition.xyz/mvNextPosition.w;
               float dotC=dot(look,dirCC);
               float dotN=dot(look,dirCN);
               if(dotC*dotN<0.){
                  if(projectionMatrix[3][3]==0.0)look=vec3(0.,0.,-1.);
               }

               vec3 crs=cross(look,dirOri);
               vec3 dir=normalize(crs);
               float aspect=computeAspect();
               dir.x*=aspect;
               float rad=width;
               if(sizeAttenuation){
                   rad*=projectionMatrix[1][1];
                  gl_Position=vec4(vec3(pmvPosition.xyz)+dir*rad/perspectiveFactor*offset,pmvPosition.w);
               }else{
                  gl_Position=vec4(vec3(pmvPosition.xyz)+dir*rad/perspectiveFactor*offset*pmvPosition.w,pmvPosition.w);
               }
               vColor=color;
               vDistance=lineDistance;
               vDrop=count;
            }
        `;
    }
    _initFragmentShader() {
        this.fragmentShader=`
            uniform float dashSize;
            uniform float gapSize;
            uniform float opacity;
            uniform bool dashFill;
            uniform float dropCorrectionHead;
            uniform float dropCorrectionTail;
            varying float vDistance;
            varying vec3 vColor;
            varying float vDrop;
            void main(){
               float md=mod(vDrop,2.0);
               if(md>1.-dropCorrectionTail||md < dropCorrectionHead){
                  discard;
               }
               if(dashFill){
                  gl_FragColor=vec4(vColor,opacity);
               }else{
                  float dev=mod(vDistance,dashSize+gapSize);
                  if(dev>dashSize){
                     discard;
                  }
                  gl_FragColor=vec4(vColor,opacity);
               }
            }
        `;
    }
}